package model;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;

/**
 * Beheert de verschillende levels op het bestandsysteem.
 */
public class LevelManager {

    private String levelStoragePath;
    private String[] levelStorageFileNames;
    private ArrayList<String> msg;

    /**
     * De constructor kijkt of er al een level directory bestaat zoniet dan maakt hij er een aan.
     */
    public LevelManager() {

        this.msg = new ArrayList<>();
        String userDirectory = System.getProperty("user.home");
        String pathSeperator = System.getProperty("file.separator");

        levelStoragePath = userDirectory + pathSeperator + "HapperJava" + pathSeperator + "levels" + pathSeperator;

        File levelStorage = new File(levelStoragePath);
        if (!levelStorage.exists()) {
            if (levelStorage.mkdirs()) {
                this.loadLevelNames();
            }
        } else {
            this.loadLevelNames();
        }
    }
    
    private void loadLevelNames() {
        File levelStorage = new File(this.levelStoragePath);
        File[] levelStorageFiles = levelStorage.listFiles();

        this.levelStorageFileNames = new String[levelStorageFiles.length];

        for (int i = 0; i < levelStorageFiles.length; i++) {
            if (levelStorageFiles[i].isFile()) {
                this.levelStorageFileNames[i] = levelStorageFiles[i].getName();
            }
        }
    }
    
    public boolean importLevel(File file) {
        String fileName;
        try {
            ObjectInputStream input;
            input = new ObjectInputStream(new FileInputStream(file));
            LevelSpecification tempLevelSpecification = (LevelSpecification) (input.readObject());
            fileName = tempLevelSpecification.getName();
        } catch (IOException | ClassNotFoundException ex) {
            this.msg.add("Importeer alleen geldige level die gebouwdt zijn met de LevelBuilder");
            return false;
        }

        Path pathToFile = Paths.get(file.getAbsolutePath());
        Path pathToImportLocation = Paths.get(levelStoragePath + fileName);

        CopyOption[] options = new CopyOption[]{
            StandardCopyOption.REPLACE_EXISTING,
            StandardCopyOption.COPY_ATTRIBUTES
        };

        try {
            Files.copy(pathToFile, pathToImportLocation, options);
        } catch (IOException ex) {
            this.msg.add(fileName + " kan niet geimporteerd worden");
            return false;
        }
        return true;
    }
    
    public boolean exportLevel(String exportPath, String fileName) {

        File file = new File(levelStoragePath + fileName);

        Path pathToFile = Paths.get(file.getAbsolutePath());
        Path pathToExportLocation = Paths.get(exportPath + System.getProperty("file.separator") + fileName);

        CopyOption[] options = new CopyOption[]{
            StandardCopyOption.REPLACE_EXISTING,
            StandardCopyOption.COPY_ATTRIBUTES
        };

        try {
            Files.copy(pathToFile, pathToExportLocation, options);
        } catch (IOException ex) {
            this.msg.add(fileName + " kan niet geexporteerd worden");
            return false;
        }
        return true;
    }
    
    public boolean save(String fileName, LevelSpecification levelSpecification, boolean overwriteExsisting) {

        if (fileName.indexOf(".dat") < 0) {
            fileName = fileName + ".dat";
        }

        if (!levelSpecification.validate()) {
            this.msg.addAll(levelSpecification.getMsg());
            return false;
        }

        try {
            String storagePath = levelStoragePath + fileName;
            File file = new File(storagePath);
            levelSpecification.setName(fileName);

            if (!overwriteExsisting) {
                if (file.exists()) {
                    this.msg.add(fileName + " bestaat gebruik een andere naam");
                    return false;
                } else {
                    file.createNewFile();
                }
            } else {
                file.createNewFile();
            }

            try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(storagePath))) {
                output.writeObject(levelSpecification);
            }
        } catch (IOException ex) {
            this.msg.add(fileName + " kan niet op geslagen worden");
            return false;
        }

        return true;
    }

    public LevelSpecification getLevelSpecificationByName(String fileName) {

        LevelSpecification tempLevelSpecification = null;
        String storagePath = levelStoragePath + fileName;

        try {
            ObjectInputStream input;
            input = new ObjectInputStream(new FileInputStream(storagePath));
            tempLevelSpecification = (LevelSpecification) (input.readObject());
        } catch (IOException | ClassNotFoundException ex) {
            this.msg.add(fileName + " kan niet op gehaald worden");
        }
        return tempLevelSpecification;

    }

    public boolean levelExist(String levelName) {

        if (levelName.indexOf(".dat") < 0) {
            levelName = levelName + ".dat";
        }

        for (String tempLevelName : levelStorageFileNames) {
            if (tempLevelName.equals(levelName)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @return the levelStorageFileNames
     */
    public String[] getLevelStorageFileNames() {
        return levelStorageFileNames;
    }

    /**
     * @return the msg
     */
    public ArrayList<String> getMsg() {
        return msg;
    }

    public void clearMsg() {
        msg = new ArrayList<>();
    }
}
